package process

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"health-check/internal/logger"

	"github.com/shirou/gopsutil/v3/process"
)

// ProcessInfo 进程信息结构体
type ProcessInfo struct {
	PID           int32     `json:"pid"`
	Name          string    `json:"name"`
	Status        string    `json:"status"`
	CPU           float64   `json:"cpu_percent"`
	Memory        float64   `json:"memory_percent"`
	Running       bool      `json:"running"`
	StartTime     time.Time `json:"start_time,omitempty"`
	LastStartTime time.Time `json:"last_start_time,omitempty"`
	StartupTime   int64     `json:"startup_time_ms,omitempty"` // 启动耗时(毫秒)
}

// ProcessRestartInfo 进程重启信息
type ProcessRestartInfo struct {
	ProcessName         string    `json:"process_name"`
	RestartCount        int       `json:"restart_count"`
	LastRestart         time.Time `json:"last_restart"`
	LastFailure         time.Time `json:"last_failure"`
	ConsecutiveFailures int       `json:"consecutive_failures"`
}

// ProcessGroupRestartInfo 进程组重启信息
type ProcessGroupRestartInfo struct {
	GroupName           string                         `json:"group_name"`
	TotalRestartCount   int                            `json:"total_restart_count"`
	FirstRestart        time.Time                      `json:"first_restart"`
	LastRestart         time.Time                      `json:"last_restart"`
	LastFailure         time.Time                      `json:"last_failure"`
	ConsecutiveFailures int                            `json:"consecutive_failures"`
	MemberRestartInfo   map[string]*ProcessRestartInfo `json:"member_restart_info"`
}

// ProcessMonitor 进程监控器
type ProcessMonitor struct {
	processes        map[string]*ProcessInfo
	restartInfo      map[string]*ProcessRestartInfo
	groupRestartInfo map[string]*ProcessGroupRestartInfo
	maxRestarts      int
	restartDelay     time.Duration
	groupManager     *ProcessGroupManager
	startTimes       map[string]time.Time // 记录进程启动时间
}

// NewProcessMonitor 创建新的进程监控器
func NewProcessMonitor() *ProcessMonitor {
	return &ProcessMonitor{
		processes:        make(map[string]*ProcessInfo),
		restartInfo:      make(map[string]*ProcessRestartInfo),
		groupRestartInfo: make(map[string]*ProcessGroupRestartInfo),
		maxRestarts:      5,               // 默认最大重启次数
		restartDelay:     5 * time.Second, // 默认重启延迟
		groupManager:     NewProcessGroupManager(),
		startTimes:       make(map[string]time.Time),
	}
}

// NewProcessMonitorWithConfig 使用配置创建进程监控器
func NewProcessMonitorWithConfig(maxRestarts int, restartDelay time.Duration) *ProcessMonitor {
	return &ProcessMonitor{
		processes:        make(map[string]*ProcessInfo),
		restartInfo:      make(map[string]*ProcessRestartInfo),
		groupRestartInfo: make(map[string]*ProcessGroupRestartInfo),
		maxRestarts:      maxRestarts,
		restartDelay:     restartDelay,
		groupManager:     NewProcessGroupManager(),
		startTimes:       make(map[string]time.Time),
	}
}

// AddProcess 添加要监控的进程
func (pm *ProcessMonitor) AddProcess(name string) {
	pm.processes[name] = &ProcessInfo{
		Name:    name,
		Status:  "unknown",
		Running: false,
	}
}

// CheckProcessByName 根据进程名检查进程是否运行
func (pm *ProcessMonitor) CheckProcessByName(processName string) (*ProcessInfo, error) {
	processes, err := process.Processes()
	if err != nil {
		return nil, fmt.Errorf("获取进程列表失败: %v", err)
	}

	for _, p := range processes {
		name, err := p.Name()
		if err != nil {
			continue
		}

		// 精确匹配进程名
		if name == processName {
			return pm.getProcessInfo(p)
		}
	}

	// 进程未找到
	return &ProcessInfo{
		Name:    processName,
		Status:  "not_found",
		Running: false,
	}, nil
}

// CheckProcessByPID 根据PID检查进程是否运行
func (pm *ProcessMonitor) CheckProcessByPID(pid int32) (*ProcessInfo, error) {
	p, err := process.NewProcess(pid)
	if err != nil {
		return &ProcessInfo{
			PID:     pid,
			Status:  "not_found",
			Running: false,
		}, nil
	}

	return pm.getProcessInfo(p)
}

// CheckProcessByCommand 根据命令检查进程是否运行
func (pm *ProcessMonitor) CheckProcessByCommand(command string) (*ProcessInfo, error) {
	processes, err := process.Processes()
	if err != nil {
		return nil, fmt.Errorf("获取进程列表失败: %v", err)
	}

	for _, p := range processes {
		cmdline, err := p.Cmdline()
		if err != nil {
			continue
		}

		// 检查命令行是否包含指定命令
		if strings.Contains(cmdline, command) {
			return pm.getProcessInfo(p)
		}
	}

	// 进程未找到
	return &ProcessInfo{
		Name:    command,
		Status:  "not_found",
		Running: false,
	}, nil
}

// getProcessInfo 获取进程详细信息
func (pm *ProcessMonitor) getProcessInfo(p *process.Process) (*ProcessInfo, error) {
	pid := p.Pid
	name, err := p.Name()
	if err != nil {
		name = "unknown"
	}

	status, err := p.Status()
	if err != nil {
		status = []string{"unknown"}
	}

	cpuPercent, err := p.CPUPercent()
	if err != nil {
		cpuPercent = 0
	}

	memPercent, err := p.MemoryPercent()
	if err != nil {
		memPercent = 0
	}

	// 检查进程是否真的在运行
	running := true
	if len(status) > 0 {
		// 检查进程状态，如果状态为Z（僵尸进程）则认为不在运行
		if status[0] == "Z" {
			running = false
		}
	}

	return &ProcessInfo{
		PID:     pid,
		Name:    name,
		Status:  strings.Join(status, ","),
		CPU:     cpuPercent,
		Memory:  float64(memPercent),
		Running: running,
	}, nil
}

// GetAllProcesses 获取所有进程信息
func (pm *ProcessMonitor) GetAllProcesses() ([]*ProcessInfo, error) {
	processes, err := process.Processes()
	if err != nil {
		return nil, fmt.Errorf("获取进程列表失败: %v", err)
	}

	var result []*ProcessInfo
	for _, p := range processes {
		info, err := pm.getProcessInfo(p)
		if err != nil {
			continue
		}
		result = append(result, info)
	}

	return result, nil
}

// IsProcessRunning 简单检查进程是否运行
func (pm *ProcessMonitor) IsProcessRunning(identifier string) (bool, error) {
	// 尝试按PID检查
	if pid, err := strconv.Atoi(identifier); err == nil {
		info, err := pm.CheckProcessByPID(int32(pid))
		if err != nil {
			return false, err
		}
		return info.Running, nil
	}

	// 按进程名检查
	info, err := pm.CheckProcessByName(identifier)
	if err != nil {
		return false, err
	}
	return info.Running, nil
}

// StartProcess 启动进程
func (pm *ProcessMonitor) StartProcess(command string, args []string) error {
	cmd := exec.Command(command, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Start()
}

// StartProcessWithEnv 使用环境变量启动进程
func (pm *ProcessMonitor) StartProcessWithEnv(command string, args []string, workDir string, env []string) error {
	cmd := exec.Command(command, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if workDir != "" {
		cmd.Dir = workDir
	}

	if len(env) > 0 {
		cmd.Env = append(os.Environ(), env...)
	}

	return cmd.Start()
}

// RestartProcess 重启进程
func (pm *ProcessMonitor) RestartProcess(processName, restartCmd string, workDir string, env []string) error {
	// 记录重启信息
	pm.recordRestartAttempt(processName)

	// 记录重启详细信息
	logger.Infof("重启进程 %s: 命令=%s, 工作目录=%s", processName, restartCmd, workDir)

	// 使用 shell 执行重启命令
	cmd := exec.Command("sh", "-c", restartCmd)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if workDir != "" {
		cmd.Dir = workDir
	}

	if len(env) > 0 {
		cmd.Env = append(os.Environ(), env...)
	}

	// 启动进程并立即分离，让进程在后台运行
	err := cmd.Start()
	if err != nil {
		return err
	}

	// 不等待进程结束，让它在后台运行
	go func() {
		cmd.Wait()
	}()

	// 等待进程启动完成
	logger.Debugf("等待进程 %s 启动完成...", processName)
	time.Sleep(3 * time.Second) // 等待3秒让进程完全启动

	return nil
}

// recordRestartAttempt 记录重启尝试
func (pm *ProcessMonitor) recordRestartAttempt(processName string) {
	info, exists := pm.restartInfo[processName]
	if !exists {
		info = &ProcessRestartInfo{
			ProcessName: processName,
		}
		pm.restartInfo[processName] = info
	}

	info.RestartCount++
	info.LastRestart = time.Now()
}

// RecordProcessFailure 记录进程失败
func (pm *ProcessMonitor) RecordProcessFailure(processName string) {
	info, exists := pm.restartInfo[processName]
	if !exists {
		info = &ProcessRestartInfo{
			ProcessName: processName,
		}
		pm.restartInfo[processName] = info
	}

	info.LastFailure = time.Now()
	info.ConsecutiveFailures++
}

// RecordProcessSuccess 记录进程成功
func (pm *ProcessMonitor) RecordProcessSuccess(processName string) {
	info, exists := pm.restartInfo[processName]
	if exists {
		info.ConsecutiveFailures = 0
	}
}

// ShouldRestart 判断是否应该重启进程
func (pm *ProcessMonitor) ShouldRestart(processName string) bool {
	info, exists := pm.restartInfo[processName]
	if !exists {
		return true
	}

	// 检查是否超过最大重启次数
	if info.RestartCount >= pm.maxRestarts {
		return false
	}

	// 检查连续失败次数
	if info.ConsecutiveFailures >= pm.maxRestarts {
		return false
	}

	// 检查重启间隔
	if time.Since(info.LastRestart) < pm.restartDelay {
		return false
	}

	return true
}

// GetRestartInfo 获取重启信息
func (pm *ProcessMonitor) GetRestartInfo(processName string) *ProcessRestartInfo {
	return pm.restartInfo[processName]
}

// GetAllRestartInfo 获取所有重启信息
func (pm *ProcessMonitor) GetAllRestartInfo() map[string]*ProcessRestartInfo {
	return pm.restartInfo
}

// ResetRestartInfo 重置重启信息
func (pm *ProcessMonitor) ResetRestartInfo(processName string) {
	delete(pm.restartInfo, processName)
}

// KillProcess 终止进程
func (pm *ProcessMonitor) KillProcess(pid int32) error {
	p, err := os.FindProcess(int(pid))
	if err != nil {
		return fmt.Errorf("找不到进程 PID %d: %v", pid, err)
	}

	return p.Kill()
}

// MonitorProcess 持续监控进程
func (pm *ProcessMonitor) MonitorProcess(identifier string, interval time.Duration, callback func(*ProcessInfo)) {
	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	for range ticker.C {
		var info *ProcessInfo
		var err error

		// 尝试按PID检查
		if pid, err := strconv.Atoi(identifier); err == nil {
			info, err = pm.CheckProcessByPID(int32(pid))
		} else {
			// 按进程名检查
			info, err = pm.CheckProcessByName(identifier)
		}

		if err != nil {
			// 创建错误信息
			info = &ProcessInfo{
				Name:    identifier,
				Status:  "error",
				Running: false,
			}
		}

		callback(info)
	}
}

// CheckProcessGroup 检查进程组状态
func (pm *ProcessMonitor) CheckProcessGroup(groupName string) (*ProcessGroupStatus, error) {
	return pm.groupManager.CheckGroupStatus(groupName, pm)
}

// AddProcessGroup 添加进程组
func (pm *ProcessMonitor) AddProcessGroup(group *ProcessGroup) error {
	if err := pm.groupManager.ValidateGroup(group); err != nil {
		return err
	}
	pm.groupManager.AddGroup(group)
	return nil
}

// GetProcessGroup 获取进程组
func (pm *ProcessMonitor) GetProcessGroup(groupName string) *ProcessGroup {
	return pm.groupManager.GetGroup(groupName)
}

// GetAllProcessGroups 获取所有进程组
func (pm *ProcessMonitor) GetAllProcessGroups() map[string]*ProcessGroup {
	return pm.groupManager.GetAllGroups()
}

// GetGroupMemberNames 获取进程组成员名称
func (pm *ProcessMonitor) GetGroupMemberNames(groupName string) ([]string, error) {
	return pm.groupManager.GetGroupMemberNames(groupName)
}

// RestartProcessGroup 重启进程组（只重启不在运行的进程）
func (pm *ProcessMonitor) RestartProcessGroup(groupName string) ([]string, error) {
	group := pm.groupManager.GetGroup(groupName)
	if group == nil {
		return nil, fmt.Errorf("进程组 %s 不存在", groupName)
	}

	members, err := pm.groupManager.GetGroupMemberNames(groupName)
	if err != nil {
		return nil, err
	}

	var errors []string
	var restartedCount int
	var restartedMembers []string

	for _, memberName := range members {
		// 检查进程是否在运行
		info, err := pm.CheckProcessByName(memberName)
		if err != nil {
			// 检查失败，尝试重启
			logger.Warnf("检查进程 %s 失败，尝试重启: %v", memberName, err)
		} else if info.Running {
			// 进程正在运行，跳过
			logger.Debugf("进程 %s 正在运行，跳过重启", memberName)
			continue
		}

		// 进程未运行，执行重启
		logger.Infof("重启进程组成员: %s", memberName)

		// 处理工作目录中的模式替换
		workDir := pm.groupManager.expandPattern(group.WorkDir, memberName)
		// 处理重启命令中的模式替换
		restartCmd := pm.groupManager.expandPattern(group.RestartCmd, memberName)

		logger.Debugf("进程组成员 %s: 原始工作目录=%s, 替换后=%s", memberName, group.WorkDir, workDir)
		logger.Debugf("进程组成员 %s: 原始重启命令=%s, 替换后=%s", memberName, group.RestartCmd, restartCmd)

		if err := pm.RestartProcess(memberName, restartCmd, workDir, group.Env); err != nil {
			errors = append(errors, fmt.Sprintf("%s: %v", memberName, err))
		} else {
			restartedCount++
			// 记录成员重启信息
			pm.RecordProcessGroupMemberRestart(groupName, memberName)

			// 等待进程启动完成后检查状态
			logger.Debugf("检查重启后的进程状态: %s", memberName)
			time.Sleep(2 * time.Second) // 额外等待2秒

			// 检查进程是否成功启动
			info, err := pm.CheckProcessByName(memberName)
			if err == nil && info.Running {
				logger.Infof("子进程 %s 重启成功", memberName)
				restartedMembers = append(restartedMembers, memberName)
			} else {
				logger.Warnf("子进程 %s 重启后状态异常: %v", memberName, err)
			}
		}
	}

	if len(errors) > 0 {
		return restartedMembers, fmt.Errorf("重启进程组 %s 时发生错误: %s", groupName, strings.Join(errors, "; "))
	}

	logger.Infof("进程组 %s 重启完成，共重启 %d 个进程", groupName, restartedCount)
	return restartedMembers, nil
}

// RestartProcessGroupAll 强制重启进程组（重启所有进程，包括正在运行的）
func (pm *ProcessMonitor) RestartProcessGroupAll(groupName string) error {
	group := pm.groupManager.GetGroup(groupName)
	if group == nil {
		return fmt.Errorf("进程组 %s 不存在", groupName)
	}

	members, err := pm.groupManager.GetGroupMemberNames(groupName)
	if err != nil {
		return err
	}

	var errors []string
	var restartedCount int

	for _, memberName := range members {
		// 先尝试停止进程（如果正在运行）
		info, err := pm.CheckProcessByName(memberName)
		if err == nil && info.Running {
			logger.Infof("停止进程组成员: %s (PID: %d)", memberName, info.PID)
			if err := pm.KillProcess(info.PID); err != nil {
				logger.Warnf("停止进程 %s 失败: %v", memberName, err)
			}
		}

		// 重启进程
		logger.Infof("重启进程组成员: %s", memberName)

		// 处理工作目录中的模式替换
		workDir := pm.groupManager.expandPattern(group.WorkDir, memberName)
		// 处理重启命令中的模式替换
		restartCmd := pm.groupManager.expandPattern(group.RestartCmd, memberName)

		if err := pm.RestartProcess(memberName, restartCmd, workDir, group.Env); err != nil {
			errors = append(errors, fmt.Sprintf("%s: %v", memberName, err))
		} else {
			restartedCount++
			// 记录成员重启信息
			pm.RecordProcessGroupMemberRestart(groupName, memberName)
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("强制重启进程组 %s 时发生错误: %s", groupName, strings.Join(errors, "; "))
	}

	logger.Infof("进程组 %s 强制重启完成，共重启 %d 个进程", groupName, restartedCount)
	return nil
}

// GetProcessGroupRestartInfo 获取进程组重启信息
func (pm *ProcessMonitor) GetProcessGroupRestartInfo(groupName string) *ProcessGroupRestartInfo {
	if info, exists := pm.groupRestartInfo[groupName]; exists {
		return info
	}
	return nil
}

// GetAllProcessGroupRestartInfo 获取所有进程组重启信息
func (pm *ProcessMonitor) GetAllProcessGroupRestartInfo() map[string]*ProcessGroupRestartInfo {
	return pm.groupRestartInfo
}

// RecordProcessGroupFailure 记录进程组失败
func (pm *ProcessMonitor) RecordProcessGroupFailure(groupName string) {
	now := time.Now()

	// 获取或创建进程组重启信息
	info, exists := pm.groupRestartInfo[groupName]
	if !exists {
		info = &ProcessGroupRestartInfo{
			GroupName:         groupName,
			MemberRestartInfo: make(map[string]*ProcessRestartInfo),
		}
		pm.groupRestartInfo[groupName] = info
	}

	info.LastFailure = now
	info.ConsecutiveFailures++
}

// RecordProcessGroupSuccess 记录进程组成功
func (pm *ProcessMonitor) RecordProcessGroupSuccess(groupName string) {
	if info, exists := pm.groupRestartInfo[groupName]; exists {
		info.ConsecutiveFailures = 0
	}
}

// RecordProcessGroupMemberRestart 记录进程组成员重启
func (pm *ProcessMonitor) RecordProcessGroupMemberRestart(groupName, memberName string) {
	now := time.Now()

	// 获取或创建进程组重启信息
	info, exists := pm.groupRestartInfo[groupName]
	if !exists {
		info = &ProcessGroupRestartInfo{
			GroupName:         groupName,
			MemberRestartInfo: make(map[string]*ProcessRestartInfo),
		}
		pm.groupRestartInfo[groupName] = info
	}

	// 获取或创建成员重启信息
	memberInfo, exists := info.MemberRestartInfo[memberName]
	if !exists {
		memberInfo = &ProcessRestartInfo{
			ProcessName: memberName,
		}
		info.MemberRestartInfo[memberName] = memberInfo
	}

	// 更新成员重启信息
	memberInfo.RestartCount++
	memberInfo.LastRestart = now

	// 更新进程组重启信息
	info.TotalRestartCount++
	info.LastRestart = now

	// 如果是第一次重启，记录首次重启时间
	if info.FirstRestart.IsZero() {
		info.FirstRestart = now
	}

	logger.Infof("记录进程组成员 %s 重启: 第 %d 次", memberName, memberInfo.RestartCount)
}

// RecordProcessStartTime 记录进程启动时间
func (pm *ProcessMonitor) RecordProcessStartTime(processName string) {
	pm.startTimes[processName] = time.Now()
}

// GetProcessStartupTime 获取进程启动耗时
func (pm *ProcessMonitor) GetProcessStartupTime(processName string) int64 {
	if startTime, exists := pm.startTimes[processName]; exists {
		return time.Since(startTime).Milliseconds()
	}
	return 0
}

// UpdateProcessStartupTime 更新进程启动时间信息
func (pm *ProcessMonitor) UpdateProcessStartupTime(processName string, procInfo *ProcessInfo) {
	if startTime, exists := pm.startTimes[processName]; exists {
		procInfo.StartupTime = time.Since(startTime).Milliseconds()
		procInfo.LastStartTime = startTime
		if procInfo.StartTime.IsZero() {
			procInfo.StartTime = startTime
		}
	}
}
